package com.jasmine.auth;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.jasmine.auth.exception.InvalidTokenException;
import com.jasmine.auth.exception.NoneTokenException;
import com.jasmine.auth.model.Token;
import com.jasmine.auth.model.UserInfo;
import com.jasmine.core.constants.BjsConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Optional;

/**
 * @author jasmineXz
 */
public class TokenManager extends AbstractTokenManager {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 生成token
     * @param user 用户
     * @return token
     */
    public Token generate (UserInfo user) {
        String accessToken = UUID.randomUUID().toString();
        // String refreshToken = UUID.randomUUID().toString();

        user.setPassword(null);

        Token token = new Token (accessToken, null, user);

        token.setAccessExpires(getDefaultAccessExpires());
        // token.setRefreshExpires(getDefaultRefreshExpires());

        saveToken(token);
        return token;
    }

    /**
     * 获取token
     * @param accessToken token
     * @return token
     */
    public Token getAccessToken (String accessToken) {
        Optional.ofNullable(accessToken).orElseThrow(NoneTokenException::new);

        String key = BjsConstants.Token.ACCESS_TOKEN + StrUtil.sub(accessToken,7,accessToken.length());
        Token token = (Token)redisTemplate.opsForValue().get(key);

        Optional.ofNullable(token).orElseThrow(InvalidTokenException::new);

        token.setAccessExpires(redisTemplate.getExpire(key));
        token.setRefreshToken(null);
        token.setRefreshExpires(null);
        return token;
    }

    /**
     * 获取刷新token
     * @param refreshToken token
     * @return token
     */
    public Token getRefreshToken (String refreshToken) {
        String key = BjsConstants.Token.REFRESH_TOKEN + refreshToken;
        Token token = (Token) redisTemplate.opsForValue().get(key);

        Optional.ofNullable(token).orElseThrow(InvalidTokenException::new);

        token.setRefreshExpires(redisTemplate.getExpire(key));
        return token;
    }

    /**
     * 保存token
     * @param token token
     */
    private void saveToken(Token token){
        saveAccessToken(token);
        // saveRefreshToken(token);
    }

    private void saveAccessToken (Token token) {
        redisTemplate.opsForValue().set(
                BjsConstants.Token.ACCESS_TOKEN + token.getAccessToken(),
                token,
                token.getAccessExpires(),
                BjsConstants.Redis.REDIS_SECONDS);
    }

    private void saveRefreshToken (Token token) {
        redisTemplate.opsForValue().set(
                BjsConstants.Token.REFRESH_TOKEN + token.getRefreshToken(),
                token,
                token.getRefreshExpires(),
                BjsConstants.Redis.REDIS_SECONDS);
    }

    public void resetToken(String accessToken) {
        String key = BjsConstants.Token.ACCESS_TOKEN + StrUtil.sub(accessToken,7,accessToken.length());
        redisTemplate.expire(
                key,
                getDefaultAccessExpires(),
                BjsConstants.Redis.REDIS_SECONDS);
    }

    /**
     * 刷新token
     * @param refreshToken 刷新 token
     * @return 新的token
     */
    public Token refresh (String refreshToken) {
        Token token = this.getRefreshToken(refreshToken);
        String accessToken = UUID.randomUUID().toString();
        token.setAccessToken(accessToken);
        token.setAccessExpires(getDefaultAccessExpires());
        this.saveAccessToken(token);
        return this.getAccessToken(BjsConstants.Token.TOKEN_PREFIX + token.getAccessToken());
    }
}
